package com.myapi.server;



import java.io.FileOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.swing.JTextPane;

import com.myapi.ModelPoker.Card;
import com.myapi.ModelPoker.CardDeck;
import com.myapi.ModelPoker.HoldEmDealer;
import com.myapi.ModelPoker.HoldEmPlayer;
import com.myapi.ModelPoker.Player;
import com.myapi.ModelPoker.PlayerHand;
import com.myapi.ModelPoker.PokerGame;
import com.myapi.ModelPoker.PotContribution;
import com.myapi.ModelPoker.Table;
import com.myapi.ModelPoker.TablePot;
import com.myapi.client.PlayerHandDAO;
import com.myapi.client.PokerService;
import com.myapi.client.PotContributionInfo;
import com.myapi.client.DAO.CardDAO;
import com.myapi.client.DAO.CardDeckDAO;
import com.myapi.client.DAO.DealerDAO;
import com.myapi.client.DAO.PlayerDAO;
import com.myapi.client.DAO.TableDAO;
import com.myapi.client.DAO.TablePotDAO;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.ButtonBase;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class PokerServiceImpl extends RemoteServiceServlet implements
PokerService {


	public static PokerServiceImpl pokerServerControler;
	/**
	 * 	Table's Information which will be send to the client 
	 */
	private TableDAO tableDAO;
	int nbclient=0;
	/**
	 * Poker Game which is running
	 */
	private static PokerGame pokerGame;  //the game that the gui is displaying
	/**
	 * Table
	 */
	private Table table;
	/**
	 * which players turn it is relative to button, button = 0
	 */
	private int playersTurn;  
	/**
	 * List of the players on the current table
	 */
	private List<Player> players;
	private boolean afterFlop;
	private int commCardCounter;
	private boolean handStarted;
	private final static int TIMEMAXPLAY=15; // 15 seconds
	private ButtonBase betAmount;
	private boolean GameCreate=false;
	private final static int  NBPLAYERS=2;
	int nbplayer=0;

	/**
	 * Get the pokerServerControler or create
	 * @return 
	 */
	public static PokerServiceImpl getpokerServerControler() {
		if(pokerServerControler == null) {
			pokerServerControler = new PokerServiceImpl();
		}
		return pokerServerControler;
	}

	public void addCommCardCouter(String Card){
		pokerServerControler.commCardCounter++;
		switch (pokerServerControler.commCardCounter) {
		case 1:
			addMessage(" Flop  : "+Card);
			break;
		case 2:
			addMessage(" Flop  : "+Card);
			break;
		case 3:
			addMessage(" Flop  : "+Card+"");
			break;
		case 4:
			addMessage(" Turn  : "+Card+"");
			break;

		case 5:
			addMessage(" River  : "+Card+"");
			break;


		default:
			break;
		}
	}

	/**
	 * Game Initialisation
	 */
	public void initGame(){
		addMessage(" Game starting");

		if(Table.MAX_PLAYERS==2)
			playersTurn = 1;
		else if(Table.MAX_PLAYERS==3)
			playersTurn = 0;
		else
			playersTurn = 3;
		afterFlop = false;
		handStarted = false;
		commCardCounter = 0;
	}

	/**
	 * Check the right
	 */
	public boolean checkPlayer(String id) {
		String tmpid=players.get(playersTurn).getId();

		return players.get(playersTurn).getId().equals(id);

	}

	/**
	 * Create Cash Game
	 * @param bigBlind 
	 * @param litleBlind 
	 */
	public void createGame(double litleBlind, double bigBlind){
		pokerGame = PokerGame.createPokerCashGame(); 
		pokerGame.setSmallBlind(litleBlind);
		pokerGame.setBigBlind(bigBlind);
	}
	/**
	 *  Start Game
	 */

	public void addPlayerChips(String name,String id,double chips){
		PokerServiceImpl pokerServerControler =PokerServiceImpl.getpokerServerControler();
		if(!pokerServerControler.GameCreate){

			pokerServerControler.createGame(1.0,2.0);
			pokerServerControler.GameCreate=true;
		}


		boolean test=pokerGame.addPlayer(name,id,chips);
		if(test){
			addMessage(getPlayerbyId(id).getName()+" sit at the table");

			pokerServerControler.nbplayer++;
			addMessage("Waiting for"+(NBPLAYERS-pokerServerControler.nbplayer)+ "players");

		}

		if(pokerServerControler.nbplayer==NBPLAYERS){
			pokerServerControler.pokerGame.startGame();
			pokerServerControler.initGame();


		}
	}

	/**
	 * Add player to the current table
	 * @param name Player's name
	 * @param id Player's id
	 * @return Return false if the table is full
	 */
	public String addPlayer(String name,String id){  
		PokerServiceImpl pokerServerControler =PokerServiceImpl.getpokerServerControler();
		if(!pokerServerControler.GameCreate){

			pokerServerControler.createGame(1.0,2.0);
			pokerServerControler.GameCreate=true;
		}


		boolean test=pokerGame.addPlayer(name,id,60);
		if(test){
			addMessage(getPlayerbyId(id).getName()+" sit at the table");

			pokerServerControler.nbplayer++;
			addMessage("Waiting for"+(NBPLAYERS-pokerServerControler.nbplayer)+ "players");

		}

		if(pokerServerControler.nbplayer==NBPLAYERS){
			pokerServerControler.pokerGame.startGame();
			pokerServerControler.initGame();


		}

		return id;
	}
	/**
	 * Increment Player turn
	 */
	public void incrementPlayersTurn() {
		playersTurn = (playersTurn + 1) % Table.MAX_PLAYERS;
		Player player = players.get(playersTurn);
		if(player.getPlayerHand().getMucked()||player.getPlayerHand().isAllIn()) {  //skip over players who have mucked
			incrementPlayersTurn();
			return;
		}

	}


	//TODO: how to determine when everyone else has folded?
	/**
	 * Get Current Player
	 */
	private Player getCurrentPlayer() {
		return players.get(playersTurn);
	}
	/**
	 * Add the list of players
	 * @param players Player's List
	 */
	public void setPlayers(List<Player> players) {
		this.players = players;
	}

	/**
	 * Start Preflop
	 */
	public void startPreflop() {
		handStarted = true;
		playersTurn = (table.getButtonPosition() + 3) % getTable().getNumPlayerHands();  //start after blinds
	}
	/**
	 * Next round
	 */
	public void startNextBetting() {
		afterFlop = true;
		playersTurn = table.getButtonPosition();  
		incrementPlayersTurn();  //start directly after button
	}

	public void setTable(Table table) {
		this.table = table;
	}

	private TableDAO getTableInfo(){

		return tableDAO;
	}
	private Table getTable() {
		return pokerServerControler.table;
	}

	/**
	 * Make a bet in the PokerGame
	 * @param Amout Amout of the bet
	 * @param checked True if the player check
	 */
	private void makeBet(double amount, boolean checked) {
		Table table = getTable();
		TablePot currentPot = table.getActivePot();
		Player player = getCurrentPlayer();
		PotContribution existingC = currentPot.getPlayerContribution(player);
		PotContribution newC;
		double totalAmount;
		if(existingC == null || checked) {
			newC = player.bet(amount, false);
			totalAmount = newC.getAmount();
		} else {
			newC = player.bet(amount - existingC.getAmount(), false);
			totalAmount = newC.getAmount() + existingC.getAmount();  //in case the newC was an all in that couldn't match the currentBet
		}
		if(table.getCurrentBet()<newC.getAmount())
			player.getPlayerHand().addRaise(newC.getAmount());
		else
			player.getPlayerHand().addCall(newC.getAmount());

		table.addPotContribution(newC, true);    
	}


	/**
	 * The current Player bet
	 * @param Amout Amout of the bet
	 * @param id Player's id
	 */
	public void Bet(Double Amout,String id){
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();
		//pokerServerControler.makeBet(Amout, false);
		if(pokerServerControler.checkPlayer(id)){
			addMessage(getPlayerbyId(id).getName()+" Raise at "+Amout);
			System.out.println(getPlayerbyId(id).getName()+" Raise at "+Amout);
			Table table = pokerServerControler.getTable();
			TablePot currentPot = table.getActivePot();
			Player player = pokerServerControler.getCurrentPlayer();
			PotContribution existingC = currentPot.getPlayerContribution(player);
			PotContribution newC;
			double totalAmount;

			if(existingC == null ) {
				pokerServerControler.makeBet(Amout, false);
			} else {
				pokerServerControler.makeBet(Amout+existingC.getAmount(), false);
			}
		}
	}

	public Player getPlayerbyId(String id){
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();
		for(int i=0;i<pokerServerControler.players.size();i++){
			if(pokerServerControler.players.get(i).getId().equals(id)){
				return pokerServerControler.players.get(i);
			}
		}
		System.out.println("Player n'existe pas ");
		return null;
	}
	/**
	 * The current Player Check
	 * @param Amout Amout of the bet
	 * @param id Player's id
	 */
	public void Check(String id){
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();
		if(pokerServerControler.checkPlayer(id)){
			addMessage(getPlayerbyId(id).getName()+" Check");
			pokerServerControler.makeBet(0, true);
		}
	}
	/**
	 * The current Player Check
	 * @param id Player's id
	 */
	public void Call(String id) {
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();
		if(pokerServerControler.checkPlayer(id)){
			addMessage(getPlayerbyId(id).getName()+" Call");
			pokerServerControler.makeBet(pokerServerControler.table.getCurrentBet(), false);

		}

	}
	/**
	 * Fold
	 */
	public void Fold(String id) {
		PokerServiceImpl pokerServerControler = PokerServiceImpl.getpokerServerControler();
		if(pokerServerControler.checkPlayer(id)){
			addMessage(getPlayerbyId(id).getName()+" Fold");
			Player player = pokerServerControler.getCurrentPlayer();
			pokerServerControler.getTable().muckAllContributions(player);
			player.muckPlayerHand();
			int activeHands = pokerServerControler.getTable().getNumActivePlayerHands();
			if(activeHands == 1) {
				pokerServerControler.getTable().getDealer().endHand();
			}
		}
	}

	public static void main(String [] arg){


		System.out.println(" Start the Test Party");
		PokerServiceImpl pokerServerControler =PokerServiceImpl.getpokerServerControler();
		pokerServerControler.update();
		pokerServerControler.createGame(1,2);
		pokerServerControler.addPlayerChips("Florian","Florian",100); //0
		pokerServerControler.addPlayerChips("Pierre","Pierre",100); //1
		pokerServerControler.addPlayerChips("Sylvain","Sylvain",100); //2
		pokerServerControler.addPlayerChips("lola","lola",100); //3


		pokerServerControler.pokerGame.startGame();
		pokerServerControler.initGame();
		ArrayList<PlayerHand> listehand=(ArrayList<PlayerHand>) pokerServerControler.table.getPlayerHands();
		Object[] cards;
		for(PlayerHand p:pokerServerControler.getTable().getPlayerHands()){
			cards=p.getCards().toArray();
			System.out.println(p.getPlayer().getName()+((Card)cards[0]).getValue()+((Card)cards[0]).getSuit()+"  "+((Card)cards[1]).getValue()+((Card)cards[1]).getSuit());
		}
		pokerServerControler.getTable().getDealer().getOddsPlayer(listehand);

		for(PlayerHand p:pokerServerControler.getTable().getPlayerHands()){
			System.out.println(p.getPlayer().getName()+p.getOdds());
			pokerServerControler.addMessageForum(p.getPlayer().getName()+" has "+p.getOdds()+"% chance to win");
		}

		pokerServerControler.Bet(20.00, "lola");
		pokerServerControler.Call("Florian");
		pokerServerControler.Call("Pierre");
		pokerServerControler.Call("Sylvain");
		//	pokerServerControler.Bet(20.00,"Pierre");
		//pokerServerControler.Bet(13.00,"Florian");
		//pokerServerControler.Call("Pierre");
		//pokerServerControler.Bet(20.00,"Sylvain");
		//		pokerServerControler.Call("Sylvain");

		pokerServerControler.Check("Pierre");
		pokerServerControler.Check("Sylvain");
		pokerServerControler.Check("lola");
		pokerServerControler.Check("Florian");

		pokerServerControler.Check("Pierre");
		pokerServerControler.Check("Sylvain");
		pokerServerControler.Check("lola");
		pokerServerControler.Check("Florian");

		pokerServerControler.Check("Pierre");
		pokerServerControler.Check("Sylvain");
		pokerServerControler.Check("lola");
		pokerServerControler.Check("Florian");

		
		for(PlayerHand playerHands:pokerServerControler.getTable().getPlayerHands()){

			System.out.println(playerHands.getPlayer().getName()+" ChipsDiff "+playerHands.getChipsDiff());
		}
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			TableDAO t=pokerServerControler.getTable().getInfo();
			pm.makePersistent(t);
		} finally {
			pm.close();
		}
		
		/*
		pokerServerControler.Bet(6.00, "Sylvain");
		pokerServerControler.Bet(6.00, "lola");
		pokerServerControler.Check("Sylvain");
		pokerServerControler.Check("lola");

		pokerServerControler.Check("Sylvain");
		pokerServerControler.Check("lola");
		pokerServerControler.Bet(10.00, "Florian"); //all in
		pokerServerControler.Bet(15.00, "Pierre");
		pokerServerControler.Bet(20.00,"Sylvain");
		pokerServerControler.Call("lola");

		pokerServerControler.Call("Pierre"); // all in
		 */

	}
	public ArrayList notify(String input){


		ArrayList array=new ArrayList();	

		return array;
	}

	public String greetServer(String input) {
		nbclient++;

		/*try {
			client.wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		return " est "+ nbclient+"   dd  " + input + "!<br><br>I am running <br><br>It looks like you are using:<br>" ;
	}

	public void addMessageForum(String message) {
		PokerServiceImpl pokerServer=PokerServiceImpl.getpokerServerControler();
		pokerServerControler.table.addMessageForum(message);


	}
	public void addMessage(String message) {
		PokerServiceImpl pokerServerControler =PokerServiceImpl.getpokerServerControler();
		pokerServerControler.addMessageForum(message);

	}

	public void getInfoPokerOdd(){
		ArrayList<PlayerHand> listehand=(ArrayList<PlayerHand>) pokerServerControler.table.getPlayerHands();
		Object[] cards;
		for(PlayerHand p:pokerServerControler.getTable().getPlayerHands()){
			cards=p.getCards().toArray();
		}
		pokerServerControler.getTable().getDealer().getOddsPlayer(listehand);

		for(PlayerHand p:pokerServerControler.getTable().getPlayerHands()){
			System.out.println(p.getPlayer().getName()+p.getOdds());
			pokerServerControler.addMessageForum(p.getPlayer().getName()+" has "+p.getOdds()+"% chance to win");

			
		}
		saveBDD();
	}

	@Override
	public void leaveTable(String id) {
		addMessage(getPlayerbyId(id).getName()+" Leave Table");

	}
	int i=0;
	@Override
	public TableDAO update() {
		reinitialiseTableInfo();
		PokerServiceImpl pokerServer=PokerServiceImpl.getpokerServerControler();
		TableDAO table = null;
		if(pokerServer.table==null){
			return null;
		}
		else{
			Table tab=pokerServer.getTable();
			table=tab.getInfo();
			table.setCurrentPlayer(pokerServer.getCurrentPlayer().getInfo());
			table.setCommCardCounter(pokerServer.commCardCounter);
			return table;
		}
	}
	
	public void saveBDD(){
		PokerServiceImpl pokerServer=PokerServiceImpl.getpokerServerControler();
		TableDAO tableDAO=pokerServer.getTable().getInfo();
		
		//	BDD.cleanBDD();
		BDD.saveTableInfo(tableDAO);
		
	}


	public void reinitialiseTableInfo() {
		tableDAO=null;

	}
	@Override
	public ArrayList<PlayerHandDAO> getStatistic(PlayerDAO player) {
			 ArrayList<PlayerHandDAO> p=new ArrayList<PlayerHandDAO>();
			
			 p=BDD.getListPlayerHandInfo(player);
			System.out.println("coucou");
			System.out.println("couc");
			 return p;
			 
	}
}

